package com.onlyxiahui.general.doc.spring.boot.util;

import java.lang.reflect.Field;

import org.springframework.aop.framework.AdvisedSupport;
import org.springframework.aop.framework.AopProxy;
import org.springframework.aop.support.AopUtils;

/**
 * Description <br>
 * Date 2020-06-11 17:42:29<br>
 * 
 * @author XiaHui [onlovexiahui@qq.com]<br>
 * @since 1.0.0
 */

public class DocAopTargetUtils {
	/**
	 * 获取 目标对象
	 * 
	 * @param proxy 代理对象
	 * @return
	 * @throws Exception
	 */
	public static Object getTarget(Object proxy) {

		if (!AopUtils.isAopProxy(proxy)) {
			// 不是代理对象
			return proxy;
		}
		try {
			if (AopUtils.isJdkDynamicProxy(proxy)) {
				return getJdkDynamicProxyTargetObject(proxy);
			} else {
				// cglib
				return getCglibProxyTargetObject(proxy);
			}
		} catch (Exception e) {
			// TODO: handle exception
		}
		return null;
	}

	private static Object getCglibProxyTargetObject(Object proxy) throws Exception {
		Object target = null;
		Field h = proxy.getClass().getDeclaredField("CGLIB$CALLBACK_0");
		if (null != h) {
			h.setAccessible(true);
			Object dynamicAdvisedInterceptor = h.get(proxy);
			if (null != dynamicAdvisedInterceptor) {
				Field advised = dynamicAdvisedInterceptor.getClass().getDeclaredField("advised");
				if (null != advised) {
					advised.setAccessible(true);
					target = ((AdvisedSupport) advised.get(dynamicAdvisedInterceptor)).getTargetSource().getTarget();
				}
			}
		}
		return target;
	}

	private static Object getJdkDynamicProxyTargetObject(Object proxy) throws Exception {
		Object target = null;
		Field h = proxy.getClass().getSuperclass().getDeclaredField("h");
		if (null != h) {
			h.setAccessible(true);
			AopProxy aopProxy = (AopProxy) h.get(proxy);

			Field advised = aopProxy.getClass().getDeclaredField("advised");

			if (null != advised) {
				advised.setAccessible(true);
				target = ((AdvisedSupport) advised.get(aopProxy)).getTargetSource().getTarget();
			}
		}
		return target;
	}
}
